'use client'

import {
	Button,
	CircularProgress,
	Divider,
	Grid,
	Typography
} from '@mui/material'
import { useQuery } from '@tanstack/react-query'
import dayjs from 'dayjs'
import { CloudUploadIcon, FolderPlus, PackageOpen, Pencil } from 'lucide-react'
import React, { useCallback, useEffect, useState } from 'react'
import { useDropzone } from 'react-dropzone'
import { toast } from 'sonner'

import { AttachCard } from '@/components/cards/attach.card'
import { AttachGroupDialog } from '@/components/dialogs/attachGroup.dialog'

import {
	type IAttach,
	type IAttachGroup,
	type IAttachPreview,
	type groupedAttachs
} from '@/types/attach.types'

import { attachService } from '@/services/attach.service'

const emptyAttachGroup: IAttachGroup = {
	id: 1,
	name: '',
	description: '',
	created_on: dayjs(),
	updated_on: dayjs()
}

export function AttachGallery({
	for_object,
	updateCounter
}: {
	for_object: {
		id: number
		name:
			| 'request'
			| 'contract'
			| 'warranty'
			| 'reclamation'
			| 'delivery'
			| 'assembly'
			| 'worker'
		count: number
	}
	updateCounter?: (count: number) => void
}) {
	const [previewed_attachments, setPreviewedAttachments] = useState<
		IAttachPreview[]
	>([])
	const [attachments, setAttachments] = useState<groupedAttachs>()
	const [attachGroups, setAttachGroups] = useState<{
		[key: number]: IAttachGroup
	}>({
		0: emptyAttachGroup
	})
	const [attachments_length, setAttachmentsLength] = useState<number>(0)
	const [attach_group_dialog_open, setAttachGroupDialogOpen] = useState<{
		[key: number]: boolean
	}>({ [0]: false })

	const {
		data: queryData,
		isError,
		isLoading,
		isRefetching
	} = useQuery<IAttach[]>({
		queryKey: ['attachs_for', for_object.name, for_object.id],
		queryFn: async () =>
			await attachService.fetchMany(for_object).then(res => res.results),
		enabled: for_object.count > 0
	})

	const splitOnGroups = useCallback((attachs: IAttach[]) => {
		const grouped: groupedAttachs = {
			0: []
		}
		for (const attach of attachs) {
			const group = attach.group ? attach.group.id : 0
			if (!attachGroups[group] && attach.group)
				attachGroups[group] = attach.group
			if (!attach_group_dialog_open[group] && group > 0)
				attach_group_dialog_open[group] = false

			if (!grouped[group] && attach.group) grouped[group] = []

			grouped[group].push(attach)
		}
		setAttachGroupDialogOpen(attach_group_dialog_open)

		return grouped
	}, [])

	const onDrop = useCallback((acceptedFiles: File[]) => {
		handleFileUpload(acceptedFiles)
	}, [])

	const dropZone = useDropzone({ onDrop, noClick: true })

	useEffect(() => {
		if (!queryData) return

		setAttachmentsLength(queryData.length)
		setAttachments(splitOnGroups(queryData))
	}, [queryData])

	useEffect(() => {
		if (updateCounter && attachments) updateCounter(attachments_length)
	}, [attachments, updateCounter])

	useEffect(() => {
		if (isError) toast.error('Не удалось загрузить вложения!')
	}, [isError])

	const handleFileUpload = (files: File[] | FileList) => {
		let fileList: File[] = []

		if (files instanceof FileList) {
			fileList = Array.from(files)
		} else if (Array.isArray(files)) {
			fileList = files
		}

		const previewsPromises = fileList.map(file => {
			const maxSize = Number(process.env.NEXT_PUBLIC_FILE_SIZE_LIMIT || 0)
			if (file.size > maxSize * 1048576) {
				toast.error(`Размер файла не должен превышать ${maxSize} МБ!`, {
					description: file.name
				})
				return
			} else {
				return new Promise<IAttachPreview>(resolve => {
					const reader = new FileReader()
					reader.onloadend = () => {
						resolve({
							id: Date.now(),
							url: typeof reader.result === 'string' ? reader.result : '',
							original_name: file.name,
							size: file.size,
							content_type: file.type,
							file: file,
							group: null
						})
					}
					reader.readAsDataURL(file)
				})
			}
		})

		Promise.all(previewsPromises).then(previews => {
			const validPreviews = previews.filter(
				val => val !== undefined
			) as IAttachPreview[]
			setPreviewedAttachments(prev => [...prev, ...validPreviews])
		})
	}

	const handleFileUploadDecline = useCallback(
		(id: number) => {
			setPreviewedAttachments(prev => prev.filter(attach => attach.id !== id))
		},
		[previewed_attachments]
	)

	const handleFileUploaded = useCallback(
		(id: number) => {
			const fileToUpload = previewed_attachments.find(
				attach => attach.id === id
			)
			if (fileToUpload) handleFileUploadDecline(id)
		},
		[previewed_attachments, handleFileUploadDecline]
	)

	const handleGroupDialogOpen = (groupId: number) => {
		setAttachGroupDialogOpen(prevState => ({
			...prevState,
			[groupId]: true
		}))
	}

	const handleGroupDialogClose = (groupId: number) => {
		setAttachGroupDialogOpen(prevState => ({
			...prevState,
			[groupId]: false
		}))
	}

	return (
		<div {...dropZone.getRootProps()}>
			<Grid
				container
				spacing={1}
			>
				{isLoading || isRefetching ? (
					<Grid
						item
						xs={12}
						sx={{
							display: 'flex',
							flexDirection: 'column',
							justifyContent: 'center',
							alignItems: 'center'
						}}
					>
						<CircularProgress size={90} />
						<Typography
							variant='h6'
							component='div'
							color='textSecondary'
						>
							Ищем вложения...
						</Typography>
					</Grid>
				) : (
					(!attachments || (attachments && attachments_length === 0)) &&
					previewed_attachments.length === 0 &&
					!isLoading &&
					!isRefetching && (
						<Grid
							item
							xs={12}
							sx={{
								display: 'flex',
								flexDirection: 'column',
								justifyContent: 'center',
								alignItems: 'center'
							}}
						>
							<PackageOpen size={100} />
							<Typography
								variant='h6'
								component='div'
								color='textSecondary'
							>
								Вложений нет
							</Typography>
						</Grid>
					)
				)}
				{!isRefetching &&
					Object.entries(attachments || {}).map(([groupId, attachs]) => (
						<React.Fragment key={groupId}>
							{attachs.length > 0 && (
								<Grid
									item
									xs={12}
								>
									<Divider>
										{attachGroups[Number(groupId)].name}
										{groupId !== '0' && groupId in attach_group_dialog_open && (
											<>
												<AttachGroupDialog
													group_data={attachGroups[Number(groupId)]}
													open={attach_group_dialog_open[Number(groupId)]}
													onClose={(group: IAttachGroup | undefined) => {
														if (group && group.id !== 0)
															setAttachGroups(old => {
																old[Number(groupId)] = group
																return old
															})

														handleGroupDialogClose(Number(groupId))
													}}
													createMode={false}
												/>
												<Button
													size='small'
													startIcon={<Pencil size={16} />}
													onClick={() => handleGroupDialogOpen(Number(groupId))}
												/>
											</>
										)}
									</Divider>
								</Grid>
							)}
							{attachs.map(attach => (
								<Grid
									item
									xs={12}
									sm={6}
									md={4}
									key={attach.id}
								>
									<AttachCard
										attach_data={attach}
										queryKey={['attachs_for', for_object.name, for_object.id]}
									/>
								</Grid>
							))}
						</React.Fragment>
					))}
				{previewed_attachments.length > 0 && (
					<Grid
						item
						xs={12}
					>
						<Divider>Не подтвержденные</Divider>
					</Grid>
				)}
				{previewed_attachments.map(attach => (
					<Grid
						item
						xs={12}
						sm={6}
						md={4}
						key={attach.id}
					>
						<AttachCard
							attach_data={attach}
							queryKey={['attachs_for', for_object.name, for_object.id]}
							upload={{
								handleDecline: handleFileUploadDecline,
								handleSuccess: handleFileUploaded
							}}
						/>
					</Grid>
				))}

				<AttachGroupDialog
					group_data={emptyAttachGroup}
					open={attach_group_dialog_open[0]}
					onClose={() => handleGroupDialogClose(0)}
					createMode={true}
				/>
				<Grid
					item
					xs={12}
					sx={{
						display: 'inline-flex',
						justifyContent: 'center',
						alignItems: 'center'
					}}
				>
					<input
						{...dropZone.getInputProps()}
						value=''
					/>
					<Button
						component='label'
						startIcon={<CloudUploadIcon />}
						color={dropZone.isDragActive ? 'warning' : 'success'}
						disabled={isRefetching || isLoading}
						onClick={dropZone.open}
					>
						{dropZone.isDragActive ? 'Ловлю! Ловлю!' : 'Загрузить файл(ы)'}
					</Button>
					<Button
						startIcon={<FolderPlus />}
						color='primary'
						onClick={() => handleGroupDialogOpen(0)}
						disabled={isRefetching || isLoading}
					>
						Новая группа
					</Button>
				</Grid>
			</Grid>
		</div>
	)
}
